package main

import "fmt"
import "reflect"

//[反射](https://gfw.go101.org/article/reflection.html)
//我们使用方法Elem来得到某些类型的元素类型。
//实际上，此方法也可以用来得到一个指针类型的基类型。
func main() {
	type A = [16]int16
	var c <-chan map[A][]byte
	tc := reflect.TypeOf(c)
	fmt.Println("tc.Kind():", tc.Kind())       // chan
	fmt.Println("tc.ChanDir():", tc.ChanDir()) // <-chan
	tm := tc.Elem()
	ta, tb := tm.Key(), tm.Elem()
	fmt.Println("tm.Kind(), ta.Kind(), tb.Kind():", tm.Kind(), ta.Kind(), tb.Kind()) // map array slice
	tx, ty := ta.Elem(), tb.Elem()

	// byte是uint8类型的别名。
	fmt.Println("tx.Kind(), ty.Kind():", tx.Kind(), ty.Kind()) // int16 uint8
	fmt.Println("tx.Bits(), ty.Bits():", tx.Bits(), ty.Bits()) // 16 8
	fmt.Println("tx.ConvertibleTo(ty):", tx.ConvertibleTo(ty)) // true
	fmt.Println("tb.ConvertibleTo(ta):", tb.ConvertibleTo(ta)) // false

	// 切片类型和映射类型都是不可比较类型。
	fmt.Println("tb.Comparable():", tb.Comparable()) // false
	fmt.Println("tm.Comparable():", tm.Comparable()) // false
	fmt.Println("ta.Comparable():", ta.Comparable()) // true
	fmt.Println("tc.Comparable():", tc.Comparable()) // true
	fmt.Println("-------DemoElemOfPointer----------")
	DemoElemOfPointer()
}

type T []interface{ m() }

func (T) m() {}

func DemoElemOfPointer() {
	tp := reflect.TypeOf(new(interface{}))
	tt := reflect.TypeOf(T{})
	fmt.Println("tp.Kind(), tt.Kind():", tp.Kind(), tt.Kind()) // ptr slice

	// 使用间接的方法得到表示两个接口类型的reflect.Type值。
	tpe, tte := tp.Elem(), tt.Elem()
	fmt.Println("tpe.Kind(), tte.Kind():", tpe.Kind(), tte.Kind()) // interface interface

	fmt.Println("tt.Implements(tte):", tt.Implements(tte)) // true
	// panic: reflect: non-interface type passed to Type.Implements
	//fmt.Println("tte.Implements(tt):", tte.Implements(tt))
	fmt.Println("tp.Implements(tte):", tp.Implements(tte))   // false
	fmt.Println("tte.Implements(tte):", tte.Implements(tte)) // true

	// 所有的类型都实现了任何空接口类型。
	fmt.Println("tp.Implements(tpe):", tp.Implements(tpe))   // true
	fmt.Println("tt.Implements(tpe):", tt.Implements(tpe))   // true
	fmt.Println("tte.Implements(tpe):", tte.Implements(tpe)) // true
	fmt.Println("tpe.Implements(tpe):", tpe.Implements(tpe)) // true
}
